﻿#pragma once
#include "yzrutil.h"
#include "DSP.h"
#include "RingBuffer.h"
#include "BufferDelayer.h"
#include "Oscillator.h"

namespace yzrilyzr_dsp{
	ECLASS(Chorus, public DSP){
	private:
	RingBufferSample buffer;
	u_sample depthMul=0;
	public:
	DSPPtr osc=nullptr;
	u_time_ms depthMs=0;//ms
	u_normal_01 wetRatio=0;//%
	u_normal_11 feedback=0;//%
	BufferDelayer::DelayFunction delayFunction=BufferDelayer::linearDelay;
	Chorus();
	Chorus(u_freq rate, u_time_ms depthInMs, u_normal_01 wetRatio, u_normal_11 feedback) :
		Chorus(std::make_shared<SineOscillator>(rate), depthInMs, wetRatio, feedback){}
	Chorus(DSPPtr osc, u_time_ms depthInMs, u_normal_01 wetRatio, u_normal_11 feedback) :
		osc(osc),
		depthMs(depthInMs),
		wetRatio(wetRatio),
		feedback(feedback){}
	u_sample procDsp(u_sample in) override{
		if(wetRatio == 0 || depthMs == 0)return in;
		u_sample delayIndex=depthMul * (1 + osc->procDsp(in));
		if(delayIndex <= 0) return in;
		u_sample delayed=delayFunction(buffer, delayIndex);
		buffer.write(in + delayed * feedback);
		return delayed * wetRatio + in * (1 - wetRatio);
	}
	void init(u_sample_rate sampleRate) override{
		osc->init(sampleRate);
		depthMul=depthMs / 1000.0 * sampleRate * 0.5;
		buffer.ensureCapacity(depthMul * static_cast<u_sample>(2.0));
	}
	void resetMemory() override{
		osc->resetMemory();
		buffer.fill(0);
	}
	std::shared_ptr<DSP> cloneDSP() override{
		return std::make_shared<Chorus>(osc->cloneDSP(), depthMs, wetRatio, feedback);
	}
	void cloneParam(DSP * obj1)override{
		if(auto other=dynamic_cast<Chorus *>(obj1)){
			wetRatio=other->wetRatio;
			osc->cloneParam(other->osc.get());
			depthMs=other->depthMs;
			feedback=other->feedback;
			delayFunction=other->delayFunction;
		}
	}
	yzrilyzr_lang::String toString()const override;
	};
}
